package com.panfeng.xcloud.boss.provider.member.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.panfeng.xcloud.boss.provider.enums.AccountNumberTypeEnum;
import com.panfeng.xcloud.boss.provider.enums.PwdTypeEnum;
import com.panfeng.xcloud.boss.provider.enums.TaskTypeEnum;
import com.panfeng.xcloud.boss.provider.enums.UserTypeEnum;
import com.panfeng.xcloud.boss.provider.member.cache.CacheContext;
import com.panfeng.xcloud.boss.provider.member.config.AppVersionItemPropConfig;
import com.panfeng.xcloud.boss.provider.member.config.AppVersionUpdatePropConfig;
import com.panfeng.xcloud.boss.provider.member.constants.LockContants;
import com.panfeng.xcloud.boss.provider.member.dao.mapper.*;
import com.panfeng.xcloud.boss.provider.member.dto.request.*;
import com.panfeng.xcloud.boss.provider.member.dto.response.*;
import com.panfeng.xcloud.boss.provider.member.enums.LoginModeEnum;
import com.panfeng.xcloud.boss.provider.member.enums.OperationTypeEnum;
import com.panfeng.xcloud.boss.provider.member.lock.RedisLock;
import com.panfeng.xcloud.boss.provider.member.model.LoginUserInfo;
import com.panfeng.xcloud.boss.provider.member.security.auth.SecurityUtils;
import com.panfeng.xcloud.boss.provider.member.security.auth.UserDetailsServiceImpl;
import com.panfeng.xcloud.boss.provider.member.service.*;
import com.panfeng.xcloud.common.core.configuration.DataDictionaryConfig;
import com.panfeng.xcloud.common.core.constants.BlConstants;
import com.panfeng.xcloud.common.core.constants.RedisConstants;
import com.panfeng.xcloud.common.core.enums.ResponseStatusEnum;
import com.panfeng.xcloud.common.core.enums.UserBaseStatusEnum;
import com.panfeng.xcloud.common.core.enums.UserLevelTypeEnum;
import com.panfeng.xcloud.common.core.exceptions.BaseBizException;
import com.panfeng.xcloud.common.core.utils.ConvertUtils;
import com.panfeng.xcloud.common.core.utils.MD5Utils;
import com.panfeng.xcloud.common.core.utils.TokenUtils;
import com.panfeng.xcloud.common.security.vo.ExtGrantedAuthority;
import com.panfeng.xcloud.common.security.vo.SysSecurityUser;
import com.panfeng.xcloud.component.ocr.OcrMaker;
import com.panfeng.xcloud.component.ocr.model.UserOcrAuthMaterialsInfo;
import com.panfeng.xcloud.dao.assets.entity.UserWalletInfo;
import com.panfeng.xcloud.dao.base.MapperSupport;
import com.panfeng.xcloud.dao.member.entity.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class UserBasicServiceImpl extends MapperSupport<Integer, UserBase, UserBaseMapperExt> implements IUserBasicService {

    @Autowired
    private CacheContext cacheContext;

    @Autowired
    private IWalletAssetsService iWalletAssetsService;

    @Autowired
    private IUserWalletInfoService iUserWalletInfoService;

    @Autowired
    private IUserTokenService iUserTokenService;

    @Resource
    private UserBaseMapperExt userBaseMapperExt;

    @Autowired
    private UserWalletInfoMapperExt userWalletInfoMapperExt;

    @Autowired
    private IUserOperaterLogService iUserOperaterLogService;

    @Resource
    private UserAccountMapperExt userAccountMapperExt;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IUserSMSService iUserSMSService;

    @Resource
    private RegisterIntegralRuleMapperExt registerIntegralRuleMapperExt;

    @Autowired
    private ISeqenceService iSeqenceService;

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.bucketname}")
    private String bucketname;

    @Resource
    private UserPwdMapperExt userpwdMapperExt;

    @Resource
    private UserInviterMapperExt userInviterMapperExt;

    @Resource
    private UserEntityMapperExt userEntityMapperExt;

    @Autowired
    private OcrMaker ocrMaker;

    @Autowired
    private AppVersionUpdatePropConfig appVersionUpdatePropConfig;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private IUserFamilyOptService iUserFamilyOptService;

    @Resource
    private DataDictionaryMapperExt dataDictionaryMapperExt;

    @Resource
    private UserTaskInfoMapperExt userTaskInfoMapperExt;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    @Qualifier("asyncExecutor")
    private Executor executor;

    @Autowired
    private DataDictionaryConfig dataDictionaryConfig;

    /**
     * 登录并获取认证中心token
     *
     * @param loginReqDTO
     * @param request
     * @return
     */
    @Override
    public LoginRespDTO loginForToken(LoginReqDTO loginReqDTO, HttpServletRequest request) {
        LoginRespDTO loginRespDTO = new LoginRespDTO();
        UserBase userBase = userBaseMapperExt.selectByLoginAccountExt(loginReqDTO.getAccountNumber());
        //UserBase userBase = userBaseMapperExt.selectByLoginAccount(loginReqDTO.getAccountNumber());
        if (null == userBase) {
            log.info(">>> 查询无法查询到用户个人信息，用户:{} <<<", loginReqDTO.getAccountNumber());
            throw new BaseBizException(ResponseStatusEnum.NOT_QUERY_USER_PERSONALINFO_ERROR);
        }

        if (userBase.getStatus() == 1) {
            log.info(">>> 该用户已被禁用，用户:{} <<<", loginReqDTO.getAccountNumber());
            throw new BaseBizException(ResponseStatusEnum.USER_PROHIBIT_ERROR);
        }

        String loginMode = loginReqDTO.getLoginMode();
        LoginModeEnum loginModeEnum = LoginModeEnum.of(loginMode);
        LoginTokenResponseDTO loginTokenResponseDTO = iUserTokenService.loginToken(loginModeEnum, loginReqDTO, request);

        log.info(">>>> 开始记录用户登录的操作日志 <<<");
        iUserOperaterLogService.asynInsertOperLog(userBase.getUserId(), UUID.randomUUID().toString(),
                OperationTypeEnum.LOGIN.getCode(), OperationTypeEnum.LOGIN.getMessage());

        log.info(">>>> 开始记录和更新用户的最新登录时间 <<<");
        this.asynUpdateLastLoginTime(userBase.getUserId());

        List<ExtGrantedAuthority> authorityList = userDetailsService.loadUserAuthorities(userBase.getUserId());
        String encryptPwd = "";

        if (LoginModeEnum.LOGIN_MODE_VERIFY_CODE.getValue().equals(loginMode)) {
            log.info(">>>> 当前登录模式为验证码模式 <<<");
            encryptPwd = MD5Utils.digest(loginReqDTO.getVerifyCode());
        } else if (LoginModeEnum.LOGIN_MODE_PWD.getValue().equals(loginMode)) {
            log.info(">>>> 当前登录模式为密码模式 <<<");
            encryptPwd = MD5Utils.digest(loginReqDTO.getPassword());
        } else {
            log.info(">>>> 当前不支持该种登录模式,请检查登录参数 <<<<");
            throw new BaseBizException(ResponseStatusEnum.NOT_SUPPORT_LOGIN_MODE_ERROR);
        }

        SysSecurityUser sysSecurityUser = new SysSecurityUser(userBase.getUserId(), loginReqDTO.getAccountNumber(), userBase.getNickname(), encryptPwd, authorityList);
        log.info(">>>> 开始处理登录后的业务数据 <<<");
        iUserTokenService.authAfterHandleData(loginTokenResponseDTO, sysSecurityUser, request, userBase);

        loginRespDTO.setUserId(userBase.getUserId());
        loginRespDTO.setToken(loginTokenResponseDTO.getAccess_token());
        loginRespDTO.setTokenType(loginTokenResponseDTO.getToken_type());
        loginRespDTO.setExpiresIn(loginTokenResponseDTO.getExpires_in());
        loginRespDTO.setRefreshToken(loginTokenResponseDTO.getRefresh_token());
        loginRespDTO.setNickname(userBase.getNickname());
        LoginUserInfo loginUserInfo = ConvertUtils.convert(userBase, LoginUserInfo.class);

        //判断是否已激活
        loginUserInfo.setIsActive(0);
        if (userBase.getStatus().equals(UserBaseStatusEnum.VALID.code))
            loginUserInfo.setIsActive(1);
        //判断是否已经设置过交易密码
        int countExchangePwd = userpwdMapperExt.queryPwdStatus(loginUserInfo.getUserId(), PwdTypeEnum.TRANS.getCode());

        loginUserInfo.setIsSetPayPwd(0);
        if (countExchangePwd > 0)
            loginUserInfo.setIsSetPayPwd(1);
        loginRespDTO.setUserLoginInfo(loginUserInfo);

        UserWalletInfo userWalletInfo = userWalletInfoMapperExt.selectByUserId(userBase.getUserId());
        loginRespDTO.setUserWalletInfo(userWalletInfo);
        return loginRespDTO;
    }

    @Override
    @Async("asyncExecutor")
    public void asynUpdateLastLoginTime(String userId) {
        log.info(">>> 更新用户最新的登录时间，userId：{} <<<", userId);
        userBaseMapperExt.updateLastLogonTime(userId);
    }

    /**
     * 查询用户基本信息
     *
     * @param userAccount (手机号或者邮箱)
     * @return
     */
    @Override
    public UserBase queryUserByUserName(String userAccount) {
        log.info(">>> 查询用户账户：{}", userAccount);
        UserBase userBase = userBaseMapperExt.selectByLoginAccount(userAccount);
        return userBase;
    }

    /**
     * 检查用户账户
     *
     * @param checkUserAccountReqDTO
     * @return
     */
    @Override
    public CheckUserAccountRespDTO checkUserAccount(CheckUserAccountReqDTO checkUserAccountReqDTO) {
        log.info(">>> 开始检查用户账户,参数:{} <<< ", (null != checkUserAccountReqDTO ? JSON.toJSONString(checkUserAccountReqDTO) : ""));
        CheckUserAccountRespDTO checkUserAccountRespDTO = new CheckUserAccountRespDTO();
        int accountCount = userAccountMapperExt.queryTotalByUserAccount(checkUserAccountReqDTO.getUserId(), checkUserAccountReqDTO.getAccountId());
        if (accountCount > 0) {
            checkUserAccountRespDTO.setCheckResult(0);
        } else {
            checkUserAccountRespDTO.setCheckResult(1);
        }
        return checkUserAccountRespDTO;
    }

    private UserBase userBaseBean2Vo(RegReqDTO regReqDTO) {
        if (regReqDTO == null) {
            return null;
        }
        UserBase userBase = new UserBase();
        ConvertUtils.copyProperties(regReqDTO, userBase);
        return userBase;
    }

    /**
     * 检查用户是否存在
     *
     * @param userBase
     * @return
     */
    private boolean checkUserExist(UserBase userBase) {
        int userCount = userBaseMapperExt.queryCountByMobile(userBase);
        if (userCount > 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取用户所在位数的积分
     *
     * @param userNum
     * @return
     */
    private int getScore(int userNum) {
        log.info(">>> 开始获取用户所在位数的积分 userNum:{}", userNum);
        int score = 0;
        List<RegisterIntegralRule> integralRuleList;
        Object obj = redisTemplate.opsForValue().get(RedisConstants.REGIST_INTEGRAL_RULE);
        if (null != obj) {
            log.info(">>>> 获取缓存中积分规则列表 <<<");
            integralRuleList = (List<RegisterIntegralRule>) obj;
        } else {
            log.info(">>> 从数据库中加载用户注册积分规则列表 <<<<");
            integralRuleList = registerIntegralRuleMapperExt.selectExtAll();
            //redisTemplate.opsForValue().set(RedisConstants.REGIST_INTEGRAL_RULE , integralRuleList);
            redisTemplate.opsForValue().set(RedisConstants.REGIST_INTEGRAL_RULE, integralRuleList, 30, TimeUnit.MINUTES);
        }
        if (null == integralRuleList || integralRuleList.isEmpty()) {
            log.error(">>>> 注册积分规则不存在");
            throw new BaseBizException(ResponseStatusEnum.INTEGRAL_RULE_NOT_EXIST);
        }
        // 计算当前用户的分数
        for (RegisterIntegralRule rule : integralRuleList) {
            if (userNum >= rule.getStartDigit() && null == rule.getEndDigit()) {
                score = rule.getScore();
                break;
            }
            if (userNum >= rule.getStartDigit() && userNum <= rule.getEndDigit()) {
                score = rule.getScore();
                break;
            }
        }
        log.info(">>> 结束获取用户所在位数的积分 score:{}", score);
        return score;
    }

    /**
     * 添加用户
     *
     * @param userBase
     * @return
     */
    private UserBase insertUserAndGet(UserBase userBase) {
        String extUserId = iSeqenceService.getExtUserId(UserTypeEnum.USER_TYPE_C.getCode());
        if (StringUtils.isEmpty(extUserId)) {
            log.error(">>>> 获取userId异常:{}>>>", extUserId);
            throw new BaseBizException(ResponseStatusEnum.GET_USER_ID_ERROR);
        }
        userBase.setUserId(extUserId);
        //String nickName = iSeqenceService.getNickName();
        //userBase.setNickname(userBase.getNickname());
        userBase.setAvatar("https://" + bucketname + "." + endpoint + "/" + BlConstants.IMG_STORE_URL + BlConstants.DEFAULT_AVATAR);
        Integer registerRank = Integer.valueOf(iSeqenceService.getRegisterRank());
        log.info(">>>> 用户：{}，昵称：{}，当前注册等级：{}", extUserId, userBase.getNickname(), registerRank);
        userBase.setRegisterRank(registerRank);
        userBase.setScore(getScore(registerRank));
        userBase.setUserType("C");
        userBase.setUserLevel(UserLevelTypeEnum.LEVEL_0.getCode());
        userBaseMapperExt.insertSelective(userBase);
        iSeqenceService.setRegisterRank(registerRank);
        return userBase;
    }

    /**
     * 初始化用户密码实体
     *
     * @param userId
     * @param pwd
     * @return
     */
    private UserPwd buildUserPwd(String userId, String pwd) {
        UserPwd userpwd = new UserPwd();
        userpwd.setUserId(userId);
        userpwd.setPwdType(PwdTypeEnum.LOGIN.getCode());
        userpwd.setPwd(MD5Utils.digest(pwd));
        return userpwd;
    }

    /**
     * 初始化用户邀请关系
     *
     * @param userId
     * @param inviteCode
     * @return
     */
    private UserInviterReqDTO initUserInviterDto(String userId, String inviteCode) {
        UserInviterReqDTO userInviterDto = new UserInviterReqDTO();
        userInviterDto.setUserId(userId);
        userInviterDto.setInviteCode(inviteCode);
        return userInviterDto;
    }

    /**
     * 初始化操作日志
     *
     * @param userId
     * @param sequenceId
     * @param operationType
     * @param operationDetail
     * @return
     */
    private UserOperationLog initUserOperationLog(String userId, String sequenceId, int operationType, String operationDetail) {
        UserOperationLog operationLog = new UserOperationLog();
        operationLog.setUserId(userId);
        operationLog.setSequenceId(sequenceId);
        operationLog.setOperationType(operationType);
        operationLog.setOperationDetail(operationDetail);
        return operationLog;
    }

    /**
     * 用户注册
     *
     * @param regReqDTO
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public RegRespDTO register(RegReqDTO regReqDTO) {
        RegRespDTO regRespDTO = new RegRespDTO();
        /*this.checkRegistCache(regReqDTO.getMobile() + regReqDTO.getEmail());
        // 校验验证码
        if (!iUserSMSService.checkVerifyCode(this.initCheckVerifyCodeReqBean(regReqDTO))) {
            log.info(">>> 注册校验验证码错误 <<<");
            throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
        }*/
        // 校验一个昵称在同一种用户类型只能注册一次
        UserBase userBase = this.userBaseBean2Vo(regReqDTO);
        if (this.checkUserExist(userBase)) {
            log.info(">>> 注册的用户已存在 <<<");
            throw new BaseBizException(ResponseStatusEnum.USER_EXIST);
        }
        // 查询邀请码是否有效
        if (StringUtils.isNotBlank(regReqDTO.getInviteCode()) &&
                !regReqDTO.getInviteCode().equals(BlConstants.INVITATION_CODE) &&
                !"adminRegister".equals(regReqDTO.getInviteCode())) {
            UserBase userBaseForInvite = userBaseMapperExt.queryUserInfo(regReqDTO.getInviteCode());
            if (null == userBaseForInvite) {
                log.info(">>> 注册的邀请码无效 <<<");
                throw new BaseBizException(ResponseStatusEnum.INVITE_CODE_ERROR);
            }
        }
        UserBase userBaseTmp = this.insertUserAndGet(userBase);
        UserPwd userpwd = this.buildUserPwd(userBase.getUserId(), regReqDTO.getPassword());
        userpwdMapperExt.insertSelective(userpwd);

        // 是否需要建立邀请关系
        if (StringUtils.isNotBlank(regReqDTO.getInviteCode()) && !regReqDTO.getInviteCode().equals(BlConstants.INVITATION_CODE)
                && (!"adminRegister".equals(regReqDTO.getInviteCode()))) {
            UserInviterReqDTO userInviterReqDTO = this.initUserInviterDto(userBase.getUserId(), regReqDTO.getInviteCode());
            this.asynBuildInviteRelation(userInviterReqDTO);
        }

        //添加用户资产信息
        iWalletAssetsService.createWalletAssets(userBase.getUserId());

        //添加操作日志
        UserOperationLog userOperationLog = this.initUserOperationLog(userBase.getUserId(),
                UUID.randomUUID().toString(), OperationTypeEnum.REG.getCode(), OperationTypeEnum.REG.getMessage());
        iUserOperaterLogService.asynInsertOperLog(userOperationLog);

        //创建用户祖族谱树
        if (!"adminRegister".equals(regReqDTO.getInviteCode())) {
            iUserFamilyOptService.asynBuildUserFamilyInfo(userBase.getUserId(), StringUtils.isNotEmpty(regReqDTO.getInviteCode()) ? regReqDTO.getInviteCode() : BlConstants.INVITATION_CODE);
        }

        //创建我的钱包
        iUserWalletInfoService.createUserWalletInfo(userBase.getUserId());

        regRespDTO.setUserId(userBase.getUserId());
        regRespDTO.setRegisterRank(userBase.getRegisterRank());
        return regRespDTO;
    }

    /**
     * 获取字典表配置
     *
     * @param getDefaultConfigReqDTO
     * @return
     */
    @Override
    public GetDefaultConfigRespDTO getDefaultConfig(GetDefaultConfigReqDTO getDefaultConfigReqDTO) {
        List<DataDictionary> dataDictionaries = dataDictionaryMapperExt.queryConfigsByKey(getDefaultConfigReqDTO.getCode());
        GetDefaultConfigRespDTO getDefaultConfigRespDTO = new GetDefaultConfigRespDTO();
        getDefaultConfigRespDTO.setDataDictionaries(dataDictionaries);
        return getDefaultConfigRespDTO;
    }

    /**
     * 修改字典表配置
     *
     * @param changeDefaultConfigReqDTO
     * @return
     */
    @Override
    public ChangeDefaultConfigRespDTO changeDefaultConfig(ChangeDefaultConfigReqDTO changeDefaultConfigReqDTO) {
        DataDictionary dataDictionary = new DataDictionary();
        dataDictionary.setCode(changeDefaultConfigReqDTO.getCode());
        dataDictionary.setName(changeDefaultConfigReqDTO.getName());
        dataDictionaryMapperExt.updateValueByKey(dataDictionary);

        Map<String, String> codeToNameMap = dataDictionaryConfig.getCodeToNameMap();
        codeToNameMap.put(changeDefaultConfigReqDTO.getCode(), changeDefaultConfigReqDTO.getName());
        dataDictionaryConfig.setCodeToNameMap(codeToNameMap);

        ChangeDefaultConfigRespDTO changeDefaultConfigRespDTO = new ChangeDefaultConfigRespDTO();
        changeDefaultConfigRespDTO.setDataDictionaries(codeToNameMap);

        return changeDefaultConfigRespDTO;
    }

    @Override
    @Async("asyncExecutor")
    public void asynBuildInviteRelation(UserInviterReqDTO userInviterDto) {
        log.info(">>>异步建立好友关系，用户userId :{},邀请码InviteCode:{}", userInviterDto.getUserId(), userInviterDto.getInviteCode());
        UserBase userBase = userBaseMapperExt.queryUserInfo(userInviterDto.getInviteCode());
        if (null == userBase) {
            log.info(">>> 当前邀请码在平台未注册，邀请码为InviteCode:{}", userInviterDto.getInviteCode());
            return;
        }
        UserInviter userInviter = new UserInviter();
        userInviter.setUserId(userInviterDto.getUserId());
        userInviter.setInviterId(userInviterDto.getInviteCode());
        userInviterMapperExt.insertSelective(userInviter);
    }

    @Override
    public IdentityOcrAuthStatusRespDTO getOcrAuditStatusByIdnumber(IdentityAuthStatusExtReqDTO identityAuthStatusExtReqDTO) {
        UserEntity userEntity = userEntityMapperExt.selectUserEntityByIdNumber(identityAuthStatusExtReqDTO.getIdNumber());
        IdentityOcrAuthStatusRespDTO identityOcrAuthStatusRespDTO = new IdentityOcrAuthStatusRespDTO();
        if (userEntity != null) {
            identityOcrAuthStatusRespDTO.setAuditStatus(userEntity.getOcrAuthStatus());
        } else {
            identityOcrAuthStatusRespDTO.setAuditStatus(0);
        }
        return identityOcrAuthStatusRespDTO;
    }

    @Override
    public QueryUserInfoRespDTO queryUserInfo(QueryUserInfoReqDTO queryUserInfoReqDTO) {
        UserBase userBase = userBaseMapperExt.queryUserInfo(queryUserInfoReqDTO.getUserId());
        if (userBase == null) {
            log.info(">>>>> 用户被禁用或不存在,用户userId:{} <<<<<", queryUserInfoReqDTO.getUserId());
            throw new BaseBizException(ResponseStatusEnum.USER_NOT_EXIST);
        }
        QueryUserInfoRespDTO queryUserInfoRespDTO = new QueryUserInfoRespDTO();

        ConvertUtils.copyProperties(userBase, queryUserInfoRespDTO);
        //判断是否已激活
        queryUserInfoRespDTO.setIsActive(0);
        if (userBase.getStatus().equals(UserBaseStatusEnum.VALID.code))
            queryUserInfoRespDTO.setIsActive(1);
        //判断是否已经设置过交易密码
        int countExchangePwd = userpwdMapperExt.queryPwdStatus(queryUserInfoReqDTO.getUserId(), PwdTypeEnum.TRANS.getCode());
        queryUserInfoRespDTO.setIsSetPayPwd(0);
        if (countExchangePwd > 0)
            queryUserInfoRespDTO.setIsSetPayPwd(1);

        log.info(">>> 查询用户基本信息响应：{}", (null != queryUserInfoRespDTO ? JSON.toJSONString(queryUserInfoReqDTO) : ""));
        return queryUserInfoRespDTO;
    }

    /**
     * 修改用户基本信息
     *
     * @param updInfoReqDTO
     * @return
     */
    @Override
    public boolean updateBasicInfo(UpdInfoReqDTO updInfoReqDTO) {
        if (updInfoReqDTO.getNickname() != null && updInfoReqDTO.getNickname().contains(" ")) {
            throw new BaseBizException(ResponseStatusEnum.NOT_PARAMTER_NULL);
        }
        if (updInfoReqDTO.getProfile() != null && updInfoReqDTO.getProfile().contains(" ")) {
            throw new BaseBizException(ResponseStatusEnum.NOT_PARAMTER_NULL);
        }

        Integer count = userBaseMapperExt.queryUserNickname(updInfoReqDTO.getNickname(), updInfoReqDTO.getUserId());
        if (count > 0) {
            log.info(">>>>> 当前昵称在平台已存在(平台昵称唯一，不允许重复)，昵称：{} <<<<<", updInfoReqDTO.getNickname());
            throw new BaseBizException(ResponseStatusEnum.NICKNAME_ERROR);
        }
        int rs = userBaseMapperExt.updateBasicInfo(updInfoReqDTO.getUserId(), updInfoReqDTO.getNickname(), updInfoReqDTO.getProfile());

        if (rs > 0) {
            log.info(">>> 更新用户基本信息成功 <<<");
        } else {
            log.info(">>> 更新用户基本信息失败 <<<");
        }

        //添加操作日志
        UserOperationLog userOperationLog = this.initUserOperationLog(updInfoReqDTO.getUserId(),
                UUID.randomUUID().toString(), OperationTypeEnum.INFOUPDATE.getCode(), OperationTypeEnum.INFOUPDATE.getMessage());

        iUserOperaterLogService.asynInsertOperLog(userOperationLog);

        return rs > 0;
    }

    /**
     * 修改账号密码
     *
     * @param updPwdReqDTO
     * @return
     */
    @Override
    public boolean updatePwd(UpdPwdReqDTO updPwdReqDTO) {
        log.info(">>> 更新密码操作，请求参数：{} <<<<", (null != updPwdReqDTO ? JSON.toJSONString(updPwdReqDTO) : ""));
        if (updPwdReqDTO.getAccountType() == 0) {
            String mobileRegexp = "^1[23456789]\\d{9}$";
            if (!updPwdReqDTO.getAccountNumber().matches(mobileRegexp)) {
                throw new BaseBizException(ResponseStatusEnum.MOBILE_ERROR);
            }
        }
        if (updPwdReqDTO.getAccountType() == 1) {
            String emailRegexp = "^([a-zA-Z0-9_\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9]{2,4})+$";
            if (!updPwdReqDTO.getAccountNumber().matches(emailRegexp)) {
                throw new BaseBizException(ResponseStatusEnum.EMAIL_ERROR);
            }
        }
        if (updPwdReqDTO.getPasswordType() == 0) {
            String loginPwdRegexp = "^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]{6,20}$";
            if (!updPwdReqDTO.getPassword().matches(loginPwdRegexp)) {
                throw new BaseBizException(ResponseStatusEnum.LOGIN_PWD_ERROR);
            }
        }
        if (updPwdReqDTO.getPasswordType() == 1) {
            String transPwdRegexp = "^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z\\d]{6,20}$";
            if (!updPwdReqDTO.getPassword().matches(transPwdRegexp)) {
                throw new BaseBizException(ResponseStatusEnum.TRANS_PWD_ERROR);
            }
        }

        if (StringUtils.isNotEmpty(updPwdReqDTO.getVerifyCode())) {
            CheckVerifyCodeReqDTO checkVerifyCodeReqDTO = new CheckVerifyCodeReqDTO(updPwdReqDTO.getAccountNumber(), updPwdReqDTO.getVerifyCode(), updPwdReqDTO.getBusinessType());
            boolean res = iUserSMSService.checkVerifyCode(checkVerifyCodeReqDTO);
            if (!res) {
                log.info(">>>>> 更新密码校验验证码错误 <<<<<");
                throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
            }
        }

        UserPwd userPwd = userpwdMapperExt.queryByUserId(updPwdReqDTO.getUserId(), updPwdReqDTO.getPasswordType());
        String newPwd = MD5Utils.digest(updPwdReqDTO.getPassword());
        if (newPwd.equals(userPwd.getPwd())) {
            log.info(">>>>> 更新密码时新旧密码不能是一致的 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.UPDATE_PWD_ERROR);
        }

        int rs = 0;
        if (updPwdReqDTO.getPasswordType() == PwdTypeEnum.LOGIN.getCode()) {
            rs = userpwdMapperExt.updatePwd(updPwdReqDTO.getUserId(), MD5Utils.digest(updPwdReqDTO.getPassword()), String.valueOf(PwdTypeEnum.LOGIN.getCode()));
        } else if (updPwdReqDTO.getPasswordType() == PwdTypeEnum.TRANS.getCode()) {
            rs = userpwdMapperExt.updatePwd(updPwdReqDTO.getUserId(), MD5Utils.digest(updPwdReqDTO.getPassword()), String.valueOf(PwdTypeEnum.TRANS.getCode()));
        }

        if (rs > 0) {
            log.info(">>> 更新密码信息成功<<<<");
        } else {
            log.info(">>> 更新密码信息失败<<<<");
        }

        UserOperationLog userOperationLog = this.initUserOperationLog(updPwdReqDTO.getUserId(),
                UUID.randomUUID().toString(), OperationTypeEnum.ACCOUNT_SECURITY.getCode(), OperationTypeEnum.ACCOUNT_SECURITY.getMessage());
        this.iUserOperaterLogService.asynInsertOperLog(userOperationLog);

        return rs > 0;
    }

    public static void main(String args[]) {
        System.out.println(MD5Utils.digest("a123456"));
    }

    /**
     * 账号安全-设置交易密码
     *
     * @param setTransPwdReqDTO
     * @return
     */
    @Override
    public boolean setTransPwd(SetTransPwdReqDTO setTransPwdReqDTO) {
        if (StringUtils.isNotEmpty(setTransPwdReqDTO.getVerifyCode())) {
            CheckVerifyCodeReqDTO checkVerifyCodeReqDTO = new CheckVerifyCodeReqDTO(setTransPwdReqDTO.getAccountNumber(), setTransPwdReqDTO.getVerifyCode(), setTransPwdReqDTO.getBusinessType());
            boolean res = iUserSMSService.checkVerifyCode(checkVerifyCodeReqDTO);
            if (!res) {
                log.info(">>>>> 设置交易密码校验验证码错误 <<<<<");
                throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
            }
        }

        // 查询是否存在交易密码
        UserPwd userPwdTmp = userpwdMapperExt.queryByUserId(setTransPwdReqDTO.getUserId(), PwdTypeEnum.TRANS.getCode());
        if (userPwdTmp != null) {
            log.info(">>>>> 当前用户：{} 的交易密码已设置，开始更新交易密码信息 <<<<<", setTransPwdReqDTO.getUserId());
            UpdPwdReqDTO updPwdReqBean = new UpdPwdReqDTO();
            updPwdReqBean.setAccountNumber(setTransPwdReqDTO.getAccountNumber());
            updPwdReqBean.setAccountType(setTransPwdReqDTO.getAccountType());
            updPwdReqBean.setBusinessType(setTransPwdReqDTO.getBusinessType());
            updPwdReqBean.setPassword(setTransPwdReqDTO.getPassword());
            updPwdReqBean.setPasswordType(PwdTypeEnum.TRANS.getCode());
            updPwdReqBean.setUserId(setTransPwdReqDTO.getUserId());
            //updPwdReqBean.setVerifyCode(setTransPwdReqDTO.getVerifyCode());
            return this.updatePwd(updPwdReqBean);
        }

        UserPwd userPwd = new UserPwd();
        userPwd.setUserId(setTransPwdReqDTO.getUserId());
        userPwd.setPwdType(PwdTypeEnum.TRANS.getCode());
        userPwd.setPwd(MD5Utils.digest(setTransPwdReqDTO.getPassword()));
        int rs = userpwdMapperExt.insertSelective(userPwd);

        if (rs > 0) {
            log.info(">>> 设置交易密码信息成功<<<<");
        } else {
            log.info(">>> 设置交易密码信息失败<<<<");
        }

        //添加操作日志
        UserOperationLog operationLog = this.initUserOperationLog(setTransPwdReqDTO.getUserId(),
                UUID.randomUUID().toString(), OperationTypeEnum.ACCOUNT_SECURITY.getCode(), OperationTypeEnum.ACCOUNT_SECURITY.getMessage());
        this.iUserOperaterLogService.asynInsertOperLog(operationLog);

        return rs > 0;
    }

    /**
     * 修改手机或者邮箱验证码
     *
     * @param updMobileEmailReqDTO
     * @return
     */
    @Override
    public boolean updateMobileEmail(UpdMobileEmailReqDTO updMobileEmailReqDTO) {
        if (updMobileEmailReqDTO.getAccountType() == 0) {
            String mobileRegexp = "^1[23456789]\\d{9}$";
            if (!updMobileEmailReqDTO.getAccountNumber().matches(mobileRegexp)) {
                throw new BaseBizException(ResponseStatusEnum.MOBILE_ERROR);
            }
        } else if (updMobileEmailReqDTO.getAccountType() == 1) {
            String emailRegexp = "^([a-zA-Z0-9_\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9]{2,4})+$";
            if (!updMobileEmailReqDTO.getAccountNumber().matches(emailRegexp)) {
                throw new BaseBizException(ResponseStatusEnum.EMAIL_ERROR);
            }
        }

        //校验密码
        UserPwd userPwd = userpwdMapperExt.queryByUserId(updMobileEmailReqDTO.getUserId(), updMobileEmailReqDTO.getPwdType());

        if (!userPwd.getPwd().equals(MD5Utils.digest(updMobileEmailReqDTO.getPassword()))) {
            throw new BaseBizException(ResponseStatusEnum.USER_PWD_INPUT_ERROR);
        }

        // 判断该号码是否是当前绑定的号码
        /*UserBase user = userBaseMapperExt.queryUserInfoExt(updMobileEmailReqDTO.getUserId());

        if(StringUtils.isNotEmpty(user.getMobile()) || StringUtils.isNotEmpty(user.getEmail())){
            if (updMobileEmailReqDTO.getAccountNumber().equals(user.getMobile()) || updMobileEmailReqDTO.getAccountNumber().equals(user.getEmail())) {
                log.info(">>>>> 更新用户手机号或者邮箱时，出现与当前绑定账号一致错误 <<<<<");
                throw new BaseBizException(ResponseStatusEnum.USER_ERROR);
            }
        }*/

        // 判断该号码或邮箱是否已注册
        /*UserBase userBase = userBaseMapperExt.selectByLoginAccountExt2(updMobileEmailReqDTO.getAccountNumber());
        if (userBase != null) {
            log.info(">>>>> 更新用户手机号或者邮箱时，查询用户已存在 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.USER_EXIST);
        }*/

        CheckVerifyCodeReqDTO checkVerifyCodeReqDTO = new CheckVerifyCodeReqDTO(updMobileEmailReqDTO.getAccountNumber(), updMobileEmailReqDTO.getVerifyCode(), updMobileEmailReqDTO.getBusinessType());
        boolean res = iUserSMSService.checkVerifyCode(checkVerifyCodeReqDTO);

        if (!res) {
            log.info(">>>>> 更新用户手机号或者邮箱时，校验验证码错误 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
        }

        int rs = 0;

        if (updMobileEmailReqDTO.getAccountType() == AccountNumberTypeEnum.MOBILE.getCode()) {
            rs = userBaseMapperExt.updateMobileEmail(updMobileEmailReqDTO.getUserId(), updMobileEmailReqDTO.getAccountNumber(), null);
        } else if (updMobileEmailReqDTO.getAccountType() == AccountNumberTypeEnum.EMAIL.getCode()) {
            rs = userBaseMapperExt.updateMobileEmail(updMobileEmailReqDTO.getUserId(), null, updMobileEmailReqDTO.getAccountNumber());
        }

        if (rs > 0) {
            log.info(">>> 更新用户手机号或者邮箱成功<<<<");
        } else {
            log.info(">>> 更新用户手机号或者邮箱失败<<<<");
        }

        UserOperationLog userOperationLog = this.initUserOperationLog(updMobileEmailReqDTO.getUserId(),
                UUID.randomUUID().toString(), OperationTypeEnum.ACCOUNT_SECURITY.getCode(), OperationTypeEnum.ACCOUNT_SECURITY.getMessage());
        this.iUserOperaterLogService.asynInsertOperLog(userOperationLog);

        return rs > 0;
    }

    /**
     * 设置谷歌验证器秘钥
     *
     * @param googleVerifierKeyReqDTO
     * @return
     */
    @Override
    public boolean setGoogleVerifierKey(GoogleVerifierKeyReqDTO googleVerifierKeyReqDTO) {
        log.info(">>> 设置谷歌验证器秘钥,参数为：{} <<<", (null != googleVerifierKeyReqDTO ? JSON.toJSONString(googleVerifierKeyReqDTO) : ""));
        int rs = userBaseMapperExt.updateGoogleVerifierKey(googleVerifierKeyReqDTO.getUserId(), googleVerifierKeyReqDTO.getGoogleVerifierKey());

        if (rs > 0) {
            log.info(">>> 设置谷歌验证器秘钥成功<<<<");
        } else {
            log.info(">>> 设置谷歌验证器秘钥失败<<<<");
        }

        UserOperationLog userOperationLog = this.initUserOperationLog(googleVerifierKeyReqDTO.getUserId(),
                UUID.randomUUID().toString(), OperationTypeEnum.ACCOUNT_SECURITY.getCode(), OperationTypeEnum.ACCOUNT_SECURITY.getMessage());
        this.iUserOperaterLogService.asynInsertOperLog(userOperationLog);

        return rs > 0;
    }

    /**
     * 查询谷歌验证器秘钥
     *
     * @param queryGoogleVerifierKeyReqDTO
     * @return
     */
    @Override
    public QueryGoogleVerifierKeyRespDTO queryGoogleVerifierKey(QueryGoogleVerifierKeyReqDTO queryGoogleVerifierKeyReqDTO) {
        String googleVerifierKey = userBaseMapperExt.queryGoogleVerifierKey(queryGoogleVerifierKeyReqDTO.getUserId());
        QueryGoogleVerifierKeyRespDTO queryGoogleVerifierKeyRespDTO = new QueryGoogleVerifierKeyRespDTO();
        queryGoogleVerifierKeyRespDTO.setGoogleVerifierKey(googleVerifierKey);
        return queryGoogleVerifierKeyRespDTO;
    }

    @Override
    public FlagRespDTO flagDistinguish(FlagReqDTO flagReqDTO) {
        log.info(">>> 修改页面状态请求参数：{}", (null != flagReqDTO ? JSON.toJSONString(flagReqDTO) : ""));
        FlagRespDTO flagRespDTO = new FlagRespDTO();
        int pwdStatus = userpwdMapperExt.queryPwdStatus(flagReqDTO.getUserId(), PwdTypeEnum.LOGIN.getCode());
        log.info(">>>用户密码状态：{}", pwdStatus);
        flagRespDTO.setLoginPwd(pwdStatus);
        int transPwdStatus = userpwdMapperExt.queryPwdStatus(flagReqDTO.getUserId(), PwdTypeEnum.TRANS.getCode());
        log.info(">>>用户交易密码状态：{}", transPwdStatus);
        flagRespDTO.setTransPwd(transPwdStatus);
        UserBase userBase = userBaseMapperExt.queryUserInfo(flagReqDTO.getUserId());
        flagRespDTO.setPhone(userBase.getMobile() != null ? 1 : 0);
        flagRespDTO.setEmail(userBase.getEmail() != null ? 1 : 0);
        flagRespDTO.setGoogleVerifier(userBase.getGoogleVerifierFlag());
        return flagRespDTO;
    }

    @Override
    public boolean updateHeadImg(UpdHeadImgReqDTO updHeadImgReqDTO) {
        int rs = userBaseMapperExt.updateHeadImg(updHeadImgReqDTO.getUserId(), updHeadImgReqDTO.getHeadImgUrl());

        if (rs > 0) {
            log.info(">>> 更新头像信息成功<<<<");
        } else {
            log.info(">>> 更新头像信息失败<<<<");
        }
        return rs > 0;
    }

    /**
     * 身份认证状态
     *
     * @param identityOcrAuthStatusReqDTO
     * @return
     */
    @Override
    public IdentityOcrAuthStatusRespDTO getAuditStatus(IdentityOcrAuthStatusReqDTO identityOcrAuthStatusReqDTO) {
        IdentityOcrAuthStatusRespDTO identityOcrAuthStatusRespDTO = new IdentityOcrAuthStatusRespDTO();
        UserEntity userEntity = userEntityMapperExt.queryAuditStatus(identityOcrAuthStatusReqDTO.getUserId());
        if (userEntity != null) {
            identityOcrAuthStatusRespDTO.setAuditStatus(userEntity.getOcrAuthStatus());
        } else {
            identityOcrAuthStatusRespDTO.setAuditStatus(0);
        }
        return identityOcrAuthStatusRespDTO;
    }

    /**
     * 重置登录密码
     *
     * @param resetLoginPwdReqDTO
     * @return
     */
    @Override
    public boolean resetLoginPwd(ResetLoginPwdReqDTO resetLoginPwdReqDTO) {
        UserBase userBase = new UserBase();

        if (resetLoginPwdReqDTO.getAccountType() == 0) {
            userBase.setMobile(resetLoginPwdReqDTO.getAccountNumber());
        } else if (resetLoginPwdReqDTO.getAccountType() == 1) {
            userBase.setEmail(resetLoginPwdReqDTO.getAccountNumber());
        }

        userBase = userBaseMapperExt.queryUserByAcct(userBase);

        if (null == userBase) {
            log.info(">>> 重置用户密码校验重置密码用户不存在 <<<");
            throw new BaseBizException(ResponseStatusEnum.USER_NOT_EXIST);
        }

        CheckVerifyCodeReqDTO checkVerifyCodeReqDTO = new CheckVerifyCodeReqDTO();
        checkVerifyCodeReqDTO.setAccountNumber(resetLoginPwdReqDTO.getAccountNumber());
        checkVerifyCodeReqDTO.setBusinessType("3");
        checkVerifyCodeReqDTO.setVerifyCode(resetLoginPwdReqDTO.getVerifyCode());
        boolean res = iUserSMSService.checkVerifyCode(checkVerifyCodeReqDTO);
        if (!res) {
            log.info(">>>>> 重置用户密码校验验证码时错误 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.VERIFICATION_ERROR);
        }
        int rs = userpwdMapperExt.updatePwd(userBase.getUserId(), MD5Utils.digest(resetLoginPwdReqDTO.getPassword()), String.valueOf(PwdTypeEnum.LOGIN.getCode()));

        if (rs > 0) {
            log.info(">>> 重置用户密码成功<<<<");
        } else {
            log.info(">>> 重置用户密码失败<<<<");
        }

        return rs > 0;
    }

    /**
     * 验证ocr实名认证次数(一天实名认证三次)
     *
     * @param userId
     */
    private void checkOcrAuthCountForDay(String userId) {
        String userOcrAuthCountKey = RedisConstants.XDCLOUD_BOSS_USEROCRAUTHCOUNT_PREFIX + userId;
        Integer userOcrAuthCount = (Integer) redisTemplate.opsForValue().get(userOcrAuthCountKey);
        if (userOcrAuthCount != null && userOcrAuthCount > 3) {
            log.error(">>> ocr实名认证次数-当天ocr实名认证次数上限, userId={}", userId);
            throw new BaseBizException(ResponseStatusEnum.USER_OCRAUTHCOUNT_ERROR);
        } else {
            redisTemplate.opsForValue().set(userOcrAuthCountKey, userOcrAuthCount == null ? 1 : userOcrAuthCount + 1, 1, TimeUnit.DAYS);
        }
    }

    /**
     * 检查用户实名认证使用的身份证号是否在平台注册过
     *
     * @param userEntityTmp
     * @param userId
     * @param identificationNumber
     */
    private void checkUserIdNumberRepeatBinding(UserEntity userEntityTmp, String userId, String identificationNumber) {
        if (null == userEntityTmp || !identificationNumber.equals(userEntityTmp.getIdNumber())) {
            int authCount = userEntityMapperExt.selectByIdNumber(identificationNumber);
            if (authCount > 0) {
                log.info(">>>>> checkUserIdNumberRepeatBinding（检查用户实名认证使用的身份证号是否在平台注册过） userId：{} 身份证号：{} 已被注册 <<<<<", userId, identificationNumber);
                throw new BaseBizException(ResponseStatusEnum.ID_CARD_REGISTERED_ERROR);
            }
        }
    }

    /**
     * 构建实名认证信息实体
     *
     * @param userId
     * @param userEntityId
     * @param ocrAuthStatus
     * @param userOcrAuthMaterialsInfo
     * @return
     */
    private UserEntity buildUserEntity(String userId, Integer userEntityId, Integer ocrAuthStatus, UserOcrAuthMaterialsInfo userOcrAuthMaterialsInfo) {
        UserEntity userEntity = new UserEntity();
        if (null != userEntityId) {
            userEntity.setId(userEntityId);
        }
        userEntity.setUserId(userId);
        userEntity.setName(userOcrAuthMaterialsInfo.getName());
        userEntity.setIdNumber(userOcrAuthMaterialsInfo.getIdentificationNumber());
        userEntity.setIdType("0");
        userEntity.setOcrAuthStatus(ocrAuthStatus);
        log.info(">>>>> buildUserEntity-构建实名认证实体信息：{} <<<<<", (null != userEntity ? JSON.toJSONString(userEntity) : ""));
        return userEntity;
    }

    /**
     * 验证ocr认证频率
     *
     * @param userId
     */
    private void checkOcrCheckFrequencyCache(String userId) {
        if (null != redisTemplate.opsForValue().get(RedisConstants.XDCLOUD_OCRCHECKFREQUENCY_CACHE + userId)) {
            log.info(">>> 限制实名认证频率，限制重复提交 :{} <<<", userId);
            throw new BaseBizException(ResponseStatusEnum.OCRCHECKFREQUENCY_REPEAT_RESUBMIT);
        }
        redisTemplate.opsForValue().set(RedisConstants.XDCLOUD_OCRCHECKFREQUENCY_CACHE + userId, userId);
        redisTemplate.expire(RedisConstants.XDCLOUD_OCRCHECKFREQUENCY_CACHE + userId, 2, TimeUnit.SECONDS);
    }

    /**
     * ocr身份认证
     *
     * @param userEntityOcrReqDTO
     * @return
     */
    @Override
    public void ocrIdentityAuthentication(UserEntityOcrReqDTO userEntityOcrReqDTO) {
        String userId = userEntityOcrReqDTO.getUserId();
        String ticketId = userEntityOcrReqDTO.getTicketId();
        Integer ocrAuthStatus = userEntityOcrReqDTO.getOcrAuthStatus();

        checkOcrCheckFrequencyCache(userId);

        String lockKey = LockContants.XDCLOUD_LOCK_OCRIDENTITYAUTHENTICATION_PREFIX + userId;
        String expireAfterTime = String.valueOf(System.currentTimeMillis() + 2000);

        boolean lock = redisLock.lock(lockKey, expireAfterTime);
        if (!lock) {
            log.error(">>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-同一个用户进行实名时添加锁，当前操作未获得锁 <<<", userId);
            throw new BaseBizException(ResponseStatusEnum.OCRIDENTITYAUTHENTICATION_NOT_LOCK_ERROR);
        }
        try {
            if (null != ocrAuthStatus && ocrAuthStatus != 1) {
                log.info(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-实名不通过，开始验证当前实名失败限制次数 <<<<<", userId);
                checkOcrAuthCountForDay(userEntityOcrReqDTO.getUserId());
            }
            UserEntity userEntityTmp = userEntityMapperExt.selectUserEntityByUserId(userId);
            if (null != userEntityTmp && userEntityTmp.getOcrAuthStatus() == 1) {
                log.error(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-已实名 <<<<<", userId);
                throw new BaseBizException(ResponseStatusEnum.ID_CARD_ERROR);
            }
            UserOcrAuthMaterialsInfo userOcrAuthMaterialsInfo = ocrMaker.getOcrUserMaterials(ticketId);
            String identificationNumber = userOcrAuthMaterialsInfo.getIdentificationNumber();
            if (StringUtils.isEmpty(identificationNumber)) {
                log.error(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-获取用户实名身份信息失败 <<<<<", userId);
                throw new BaseBizException(ResponseStatusEnum.GET_ID_CARD_ERROR);
            }
            log.info(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{} - 身份证号：{}-已获取到实名认证信息 <<<<<", userId, identificationNumber);
            checkUserIdNumberRepeatBinding(userEntityTmp, userId, identificationNumber);
            if (null != userEntityTmp) {
                log.info(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-曾经实名过-更新实名记录 <<<<<", userId, identificationNumber);
                UserEntity userEntity = this.buildUserEntity(userId, userEntityTmp.getId(), ocrAuthStatus, userOcrAuthMaterialsInfo);
                int result = userEntityMapperExt.updateByPrimaryKeySelective(userEntity);
                if (ocrAuthStatus == 1 && result > 0) {
                    UserTaskInfo userTaskInfo = userTaskInfoMapperExt.queryUserTaskInfo(String.valueOf(TaskTypeEnum.IDENTITY_AUTHENTICATION.getCode()), userId);
                    if (null != userTaskInfo && userTaskInfo.getStatus() == 0) {
                        log.info(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-用户实名认证用户任务-完成 <<<<<", userId, identificationNumber);
                        return;
                    }
                    log.info(">>>>> aocrIdentityAuthentication-用户{}-实名认证通过后执行更新实名认证任务状态-曾实名过 <<<<<", userId);
                    try {
                        executor.execute(new Runnable() {
                            @Override
                            public void run() {
                                asynSendXdInviterForRealName(userId);
                            }
                        });
                    } catch (Exception e) {
                        log.error(">>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-实名之后的操作异常：{} <<<", userId, e);
                        e.printStackTrace();
                    }
                }
            } else {
                log.info(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-未曾实名过-新增实名记录 <<<<<", userId, identificationNumber);
                UserEntity userEntity = this.buildUserEntity(userId, null, ocrAuthStatus, userOcrAuthMaterialsInfo);
                int result = userEntityMapperExt.insertSelective(userEntity);
                if (ocrAuthStatus == 1 && result > 0) {
                    UserTaskInfo userTaskInfo = userTaskInfoMapperExt.queryUserTaskInfo(String.valueOf(TaskTypeEnum.IDENTITY_AUTHENTICATION.getCode()), userId);
                    if (null != userTaskInfo && userTaskInfo.getStatus() == 0) {
                        log.info(">>>>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-用户实名认证用户任务-完成 <<<<<", userId, identificationNumber);
                        return;
                    }
                    log.info(">>>>> aocrIdentityAuthentication-用户{}-实名认证通过后执行更新实名认证任务状态-未曾实名过 <<<<<", userId);
                    try {
                        executor.execute(new Runnable() {
                            @Override
                            public void run() {
                                asynSendXdInviterForRealName(userId);
                            }
                        });
                    } catch (Exception e) {
                        log.error(">>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-实名之后的操作异常：{} <<<", userId, e);
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            log.error(">>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-实名认证操作失败 <<<", userId);
            e.printStackTrace();
            throw e;
        } finally {
            log.info(">>> ocrIdentityAuthentication-ocr身份认证时认证用户userId：{}-同一个用户进行实名时添加锁，实名操作完毕释放锁 <<<", userId);
            redisLock.unlock(lockKey, expireAfterTime);
        }
    }

    @Override
    @Async("asyncExecutor")
    public void asynSendXdInviterForRealName(String userId) {
        try {
            log.info(">>> 开始异步发放注册邀请奖励,用户：{}<<<<", userId);
            UserInviter userInviter = userInviterMapperExt.queryParentInviter(userId);
            if (null != userInviter) {
            } else {
                log.info(">>> 未查到邀请关系信息，说明是平台第一层邀请人，上级为平台内部邀请码a00000,因此不发放糖果,用户：{}<<<<", userId);
            }
        } catch (Exception e) {
            log.error(">>> asynSendXdInviterForRealName异常,用户：{}<<<<", userId);
            e.printStackTrace();
        }
    }

    /**
     * 查询当前ocr身份认证当前限制次数
     *
     * @param queryOcrAuthCountReqDTO
     * @return
     */
    @Override
    public QueryOcrAuthCountRespDTO queryCurrentOcrAuthCount(QueryOcrAuthCountReqDTO queryOcrAuthCountReqDTO) {
        String userId = queryOcrAuthCountReqDTO.getUserId();
        String userOcrAuthCountKey = RedisConstants.XDCLOUD_BOSS_USEROCRAUTHCOUNT_PREFIX + userId;
        Integer userOcrAuthCount = (Integer) redisTemplate.opsForValue().get(userOcrAuthCountKey);
        userOcrAuthCount = null != userOcrAuthCount ? userOcrAuthCount : 0;
        log.info(">>>> 查询当前用户ocr身份认证限制次数，用户id:{} 当前次数为：{} <<<", userId, userOcrAuthCount);
        QueryOcrAuthCountRespDTO queryOcrAuthCountRespDTO = new QueryOcrAuthCountRespDTO();
        queryOcrAuthCountRespDTO.setUserId(userId);
        //认证ID, 由使用方指定, 发起不同的认证任务需要更换不同的认证ID
        String ticketId = UUID.randomUUID().toString();
        if (userOcrAuthCount > 3) {
            log.info(">>>> 获取阿里云实名认证token，用户id:{} 已经操作限制次数3次 <<<", userId);
            queryOcrAuthCountRespDTO.setOcrToken("");
            queryOcrAuthCountRespDTO.setTicketId("");
            queryOcrAuthCountRespDTO.setIsOverride(true);
        } else {
            String ocrToken = ocrMaker.getOcrToken(ticketId);
            log.info(">>>> 获取阿里云实名认证token，用户id:{} ocrToken:{} <<<", userId, ocrToken);
            queryOcrAuthCountRespDTO.setOcrToken(ocrToken);
            queryOcrAuthCountRespDTO.setTicketId(ticketId);
            queryOcrAuthCountRespDTO.setIsOverride(false);
        }
        return queryOcrAuthCountRespDTO;
    }

    @Override
    public CheckAppVersionRespDTO checkAppVersion(CheckAppVersionReqDTO checkAppVersionReqDTO) {
        log.info(">>> 当前app版本更新：{}", (null != checkAppVersionReqDTO ? JSON.toJSONString(checkAppVersionReqDTO) : ""));
        CheckAppVersionRespDTO checkAppVersionRespDTO = new CheckAppVersionRespDTO();
        checkAppVersionRespDTO.setEnableForcedUpdated(false);
        Integer clientType = checkAppVersionReqDTO.getClientType();
        AppVersionItemPropConfig appVersionItemPropConfig = null;
        if (clientType == 1) {
            appVersionItemPropConfig = appVersionUpdatePropConfig.getAndroid();
        } else if (clientType == 2) {
            appVersionItemPropConfig = appVersionUpdatePropConfig.getIos();
        } else {
            log.error(">>>>> 获取当前app版本更新配置异常，不存在该客户端类型配置 <<<<<");
            throw new BaseBizException(ResponseStatusEnum.GET_APPVERSION_ERROR);
        }
        log.info(">>> 当前配置客户端配置：{} <<<", (null != appVersionItemPropConfig ? JSON.toJSONString(appVersionItemPropConfig) : ""));
        String enabled = appVersionItemPropConfig.getEnabled();
        if (!StringUtils.isEmpty(enabled) && "true".equals(enabled)) {
            String enableForcedUpdated = appVersionItemPropConfig.getEnableForcedUpdated();
            String clientAppVersion = checkAppVersionReqDTO.getAppVersion();
            String versionCode = appVersionItemPropConfig.getVersionCode();
            String versionName = appVersionItemPropConfig.getVersionName();
            String tipsContent = appVersionItemPropConfig.getTipsContent();
            String dowoloadUrl = appVersionItemPropConfig.getDowoloadUrl();
            if (!StringUtils.isEmpty(enableForcedUpdated) && "true".equals(enableForcedUpdated)) {
                log.info(">>> 开始强制更新app <<<");
                checkAppVersionRespDTO.setEnableForcedUpdated(true);
                checkAppVersionRespDTO.setVersionCode(versionCode);
                checkAppVersionRespDTO.setVersionName(versionName);
                checkAppVersionRespDTO.setTipsContent(tipsContent);
                checkAppVersionRespDTO.setDowoloadUrl(dowoloadUrl);
                return checkAppVersionRespDTO;
            }
            if (!StringUtils.isEmpty(clientAppVersion) && !clientAppVersion.equals(versionCode)) {
                log.info(">>> 当前客户端app版本：{} 与服务端更新版本：{} 不一致，设置app版本更新 <<<", clientAppVersion, versionCode);
                checkAppVersionRespDTO.setEnableForcedUpdated(false);
                checkAppVersionRespDTO.setVersionCode(versionCode);
                checkAppVersionRespDTO.setVersionName(versionName);
                checkAppVersionRespDTO.setTipsContent(tipsContent);
                checkAppVersionRespDTO.setDowoloadUrl(dowoloadUrl);
                return checkAppVersionRespDTO;
            }
        }
        return checkAppVersionRespDTO;
    }

    /**
     * 刷新token
     *
     * @param refreshTokenReqDTO
     * @param request
     * @return
     */
    @Override
    public RefreshTokenRespDTO refreshToken(RefreshTokenReqDTO refreshTokenReqDTO, HttpServletRequest request) {
        String tokenReqString = iUserTokenService.refreshToken(refreshTokenReqDTO.getClientId(), refreshTokenReqDTO.getClientSecret(), refreshTokenReqDTO.getRefreshToken(), request);
        JSONObject jsonObj = JSON.parseObject(tokenReqString);
        if (null != jsonObj) {
            //{"error":"invalid_token","error_description":"Encoded token is not a refresh token"}
            if (jsonObj.containsKey("error")) {
                log.info(">>> 刷新token失败，失败信息：{}", tokenReqString);
                throw new BaseBizException(ResponseStatusEnum.REFRESHTOKEN_OPT_ERROR);
            }

            String access_token = (String) jsonObj.get("access_token");
            String token_type = (String) jsonObj.get("token_type");
            String refresh_token = (String) jsonObj.get("refresh_token");
            Integer expires_in = (Integer) jsonObj.get("expires_in");
            String scope = (String) jsonObj.get("scope");

            LoginTokenResponseDTO loginTokenResponseDTO = new LoginTokenResponseDTO();

            loginTokenResponseDTO.setAccess_token(access_token);
            loginTokenResponseDTO.setExpires_in(expires_in);
            loginTokenResponseDTO.setRefresh_token(refresh_token);
            loginTokenResponseDTO.setScope(scope);
            loginTokenResponseDTO.setToken_type(token_type);

            SysSecurityUser currentSecurityUser = SecurityUtils.getCurrentSecurityUser();
            String oldToken = TokenUtils.getToken(request);
            log.info(">>> 刷新token时需要重关联用户认证信息SysSecurityUser，先根据oldToken清除老数据，再重新关联新数据 <<<<");
            cacheContext.removeLoginUserInfo(oldToken);

            UserBase userBase = userBaseMapperExt.queryUserInfo(currentSecurityUser.getUserId());

            if (null == userBase) {
                log.info(">>> 刷新token用户不存在 <<<");
                throw new BaseBizException(ResponseStatusEnum.USER_NOT_EXIST);
            }

            iUserTokenService.authAfterHandleData(loginTokenResponseDTO, currentSecurityUser, request, userBase);

            RefreshTokenRespDTO refreshTokenRespDTO = new RefreshTokenRespDTO();
            refreshTokenRespDTO.setRefreshToken(refresh_token);
            refreshTokenRespDTO.setToken(access_token);
            return refreshTokenRespDTO;
        } else {
            throw new BaseBizException(ResponseStatusEnum.UNAUTHORIZED);
        }
    }

    /**
     * 查询账号是否存在
     *
     * @param accountNumberStatusReqDTO
     * @return
     */
    @Override
    public AccountNumberStatusRespDTO queryAccountNumberStatus(AccountNumberStatusReqDTO accountNumberStatusReqDTO) {
        AccountNumberStatusRespDTO accountNumberStatusRespDTO = new AccountNumberStatusRespDTO();
        accountNumberStatusRespDTO.setStatus(userBaseMapperExt.selectByLoginAccount(accountNumberStatusReqDTO.getAccountNumber()) == null ? 0 : 1);
        return accountNumberStatusRespDTO;
    }

    /**
     * 检查注册缓存key,主要用于解决重复提交问题
     *
     * @param registCacheKey
     * @return
     */
    private void checkRegistCache(String registCacheKey) {
        if (null != redisTemplate.opsForValue().get(RedisConstants.REGIST_CACHE + registCacheKey)) {
            log.info(">>> 检查注册重复提交问题 <<<");
            throw new BaseBizException(ResponseStatusEnum.REPEAT_RESUBMIT);
        }
        redisTemplate.opsForValue().set(RedisConstants.REGIST_CACHE + registCacheKey, registCacheKey);
        redisTemplate.expire(RedisConstants.REGIST_CACHE + registCacheKey, 10, TimeUnit.SECONDS);
    }

}
